/****************************************************************************
**
** This file is part of qPhotoTag, a photo keywording application
**
** Copyright (C) 2009 Marcell Lengyel <miketkf@gmail.com>
**
** GNU General Public License
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
** as published by the Free Software Foundation; either version 2
** of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
**
****************************************************************************/

#ifndef __PHOTO_H__
#define __PHOTO_H__
/*! \file photo.h
    \brief This file contains the declaration of the Photo class

    This file includes the exiv2 headers and has class methods that
    manipulate the EXIF and IPTC data using the exiv2 library.
 */

#pragma GCC visibility push(default)
#include <exiv2/image.hpp>
#include <exiv2/exif.hpp>
#pragma GCC visibility pop

/*! \def EXIV2_TEST_VERSION(major,minor,patch)
  Returns the version number of the exiv2 library
 */
#ifdef EXIV2_VERSION
#    ifndef EXIV2_TEST_VERSION
#        define EXIV2_TEST_VERSION(major,minor,patch) \
         ( EXIV2_VERSION >= EXIV2_MAKE_VERSION(major,minor,patch) )
#    endif
#else
#    define EXIV2_TEST_VERSION(major,minor,patch) (false)
#endif

#include <string>
#include <QtCore>

//! A class for manipulating photo file data
/*!
  The Photo class stores information about the absolute path to the phtot file,
  has access to the photo's EXIF and IPTC metadata and it can be used to
  manipulate that data.
 */
class Photo
{
public:
    //! Constructor
    /*!
      The constructor stores the full path to the image file, extracts the EXIF
      and IPTC metadata, stores the EXIF thumbnail data and the IPTC Caption.

      \param filename is the full path (absolute path) to the image file
     */
    Photo(const QString &filename);
    //! Saves the metadata back to the image file
    /*!
      This method checks if the metadata was changed for the image file and if yes,
      then it saves it back to the image file. It preserves the original file
      modification date.
     */
    void save_all();
    //! Sets a new IPTC Caption for the photo
    /*!
      Sets caption_text as the new IPTC Caption for the photo. The save_needed
      flag will be set to true as well.

      \param caption_text is the new IPTC Caption string
     */
    void set_caption(const QString &caption_text);
    //! Returns the IPTC Caption tag
    /*!
      This method returns the current IPTC Caption for the photo.

      \return IPTC Caption in a QString
     */
    QString get_caption() const;
    //! Returns a list of all IPTC keywords
    /*!
      This method reads the Iptc.Application2.Keywords from the photo, assumes that
      the keywords are using a \a latin2 encoding, converts them to QString and
      returns a list with all keywords.

      \return a list of IPTC keywords
     */
    QStringList get_keywords() const;
    //! Set and/or remove IPTC keywords
    /*!
      This method can be used to remove IPTC keywords from the existing set or add
      new keywords to the set. It takes care not to add any duplicates.
      The keywords are truncated to 64 characters (IPTC limitation) and encoded to
      latin2.

      \param oldKeywords is a list of keywords to be removed
      \param newKeywords is a list of keywords to be added
      \return true if the operation was successful
     */
    bool set_keywords(const QStringList& oldKeywords, const QStringList& newKeywords);
    //! Checks if the photo has GPS information
    /*!
      This method checks if the photo's EXIF metadata has valid Exif.GPSInfo.GPSLongitude
      and Exif.GPSInfo.GPSLatitude tags.

      \return true if the EXIF info has GPS coordinates
     */
    bool has_georeference();
    //! Returns the EXIF thumbnail image
    /*!
      This method returns the JPEG thumbnail image that was extracted from the photo in
      the constructor.

      \return the JPEG thumbnail image
     */
    std::string get_thumbnail();
    //! Checks if the photo has a thumbnail in the EXIF header
    /*!
      This method returns true if the photo has a thumbnail image stored in the EXIF data.
      The thumbnail is extracted from the photo in the constructor, this time only the
      buffer size is used to decide if the thumbnail image is availabe or not.

      \return true if an EXIF thumbnail is available
     */
    bool has_thumbnail();
    //! Returns the absolute path to the image file
    /*!
      This method return the absolue path to the photo.

      \return the full/absolute path to the image file
     */
    QString get_fullpath() const;
    //! Sets the GPS coordinates for a photo
    /*!
      This method is taken from the libkexiv2 library. It removes the possibly existing
      old geocoding information and sets the new one. The altitude is only set if it is
      not 0. It sets the save_needed flag to true.

      \param altitude is the GPS Altutude information
      \param latitude is the GPS Latitude information
      \param longitude is the GPS Longitude information
      \return true if the set was successful
      \sa removeGPSInfo(), convertToRational() and save_needed
     */
    bool setGPSInfo(double altitude, double latitude, double longitude);
private:
    //! Get the contents of an EXIF tag
    /*!
      This method is taken from the libkexiv2 library. It returns the data value for
      the requested EXIF tag in a buffer. It is used for extracting the EXIF thumbnail
      data.

      \param exifTagName is a constant character pointer with the EXIF tag name
      \return a QByteArra with the EXIF tag data
     */
    QByteArray getExifTagData(const char* exifTagName) const;
    //! Get the GPS Longitude information
    /*!
      This method is taken from the libkexiv2 library. It returns true if the photo's
      EXIF metadata contains GPS information (Exif.GPSInfo.GPSLongitude and
      Exif.GPSInfo.GPSLongitudeRef tags exist and contain valid information) then it
      returns the longitude coordinate in the "longitude" attribte and true for the method
      retrn value.

      \param longitude is the Longitude GPS coordinate
      \return true if the coordinate exists and valid
     */
    bool getGPSLongitudeNumber(double *longitude) const;
    //! Get the GPS Latitude information
    /*!
      This method is taken from the libkexiv2 library. It returns true if the photo's
      EXIF metadata contains GPS information (Exif.GPSInfo.GPSLatitude and
      Exif.GPSInfo.GPSLatitudeRef tags exist and contain valid information) then it
      returns the latitude coordinate in the "latitude" attribte and true for the method
      retrn value.

      \param latitude is the Latitude GPS coordinate
      \return true if the coordinate exists and valid
     */
    bool getGPSLatitudeNumber(double *latitude) const;
    //! Get an IPTC tag's value as a string
    /*!
      This method is taken from the libkexiv2 library. It returns the value of the
      requested IPTC tag in q QString. It assumes that the encoding of the data is
      latin2. If the \a escapeCR attribute is set to true then the new line characters
      in the data are converted to spaces.

      \param iptcTagName is a constant character buffer that contains the IPTC tag name
      \param escapeCR if true then the new line characters are replaced by spaces
      \return the IPTC tag value as a string
     */
    QString getIptcTagString(const char* iptcTagName, bool escapeCR) const;
    //! Sets an IPTC tag's value
    /*!
      This method is taken from the libkexiv2 library. It sets an IPTC tag to the
      string value given in the \a value attribute. Returns true if the set was
      successful. It encodes the value to \a latin2 before saving it.

      \param iptcTagName the to set
      \param value the value to set to the tag
      \return true if the set was successful
     */
    bool setIptcTagString(const char *iptcTagName, const QString& value);
    //! Removes the current GPS information from a photo's EXIF info
    /*!
      This method is taken from the libkexiv2 library. It removes all geocoding
      info from the EXIF metadata.

      \return true if the removal was successful
     */
    bool removeGPSInfo();
    //! Converts a decimal number to fraction
    /*!
      This method is taken from the libkexiv2 library. This function converts the
      given decimal number to a rational (fractional) number.

      \param number is the decimal number to convert
      \param numerator is the numerator part of the fraction (return value)
      \param denominator is the denominator part of the fraction (return value)
      \param rounding tells how many decimal places to use
     */
    void convertToRational(double number, long int* numerator, long int* denominator, int rounding);
#pragma GCC visibility push(default)
    //! Metadata container
    Exiv2::Image::AutoPtr image;
    //! EXIF data
    Exiv2::ExifData exif_data;
    //! IPTC data
    Exiv2::IptcData iptc_data;
#pragma GCC visibility pop
    //! Thumbnail buffer
    std::string tn_data;
    //! Thumbnail size
    long tn_len;
    //! IPTC Caption/Abstract
    QString	caption;
    //! Absolute path to the image file
    QString fullpath;
    //! True, if the image has GPS data
    bool has_georef;
    //! True if there is changed metadata that should be saved
    bool save_needed;
};

#endif // __PHOTO_H__
